﻿Imports System.Management
Imports System.IO
Imports System.Threading
Imports System.Security.Principal
Imports GASS.CUDA

Public Class clsHWInfo
    Private Message As frmMessage
    Private _X64 As Boolean, _intCpuCount As Int16, _intCpuCoresTotal As Int16, _strCpuName As String, _strOSName As String, _OsSupported As Boolean
    Private _strUserName As String, _IsAdmin As Boolean, _HasAffintyChanger As Boolean
    Private _SmpCores As Int16, _DestFolder As String, _DoExtended As Boolean, _mVersion As System.Version
    Private _Password As String = vbNullString
    Public Enum eWindowsPlatform
        WindowsXP = 1
        Windows2003 = 2
        WindowsVista2008 = 3
    End Enum
    Private _WinPlatform As eWindowsPlatform
    Private Declare Function GetDiskFreeSpaceEx Lib "kernel32" Alias "GetDiskFreeSpaceExA" (ByVal lpDirectoryName As String, ByRef lpFreeBytesAvailableToCaller As Long, ByRef lpTotalNumberOfBytes As Long, ByRef lpTotalNumberOfFreeBytes As Long) As Long
    Public Property AccPassword() As String
        Get
            Return _Password
        End Get
        Set(ByVal value As String)
            _Password = value
        End Set
    End Property
    Public ReadOnly Property MyVersion() As System.Version
        Get
            Return My.Application.Info.Version
        End Get
    End Property
    Public ReadOnly Property WindowsPlatform() As eWindowsPlatform
        Get
            Return _WinPlatform
        End Get
    End Property
    Private _ht As Boolean = False
    Public Property HasHT() As Boolean
        Get
            Return _ht
        End Get
        Set(ByVal value As Boolean)
            _ht = value
        End Set
    End Property
    Public Function GetFreeSpace(ByVal Drive As String) As Long
        Dim lBytesTotal, lFreeBytes, lFreeBytesAvailable As Long
        Dim iAns As Long
        iAns = GetDiskFreeSpaceEx(Drive, lFreeBytesAvailable, _
             lBytesTotal, lFreeBytes)
        If ians > 0 Then

            Return BytesToMegabytes(lFreeBytes)
        Else
            Throw New Exception("Invalid or unreadable drive")
        End If
    End Function
    Public Function GetTotalSpace(ByVal Drive As String) As String
        Dim lBytesTotal, lFreeBytes, lFreeBytesAvailable As Long
        Dim iAns As Long
        iAns = GetDiskFreeSpaceEx(Drive, lFreeBytesAvailable, _
             lBytesTotal, lFreeBytes)
        If iAns > 0 Then
            Return BytesToMegabytes(lBytesTotal)
        Else
            Throw New Exception("Invalid or unreadable drive")
        End If
    End Function

    Private Function BytesToMegabytes(ByVal Bytes As Long) As Long
        Dim dblAns As Double
        dblAns = (Bytes / 1024) / 1024
        BytesToMegabytes = Format(dblAns, "###,###,##0.00")
    End Function

    Public ReadOnly Property DestinationFolder() As String
        Get
            Return _DestFolder
        End Get
    End Property
    Public Property SmpC() As String
        Get
            Return _SmpCores.ToString
        End Get
        Set(ByVal value As String)
            _SmpCores = CInt(value)
        End Set
    End Property
    Public ReadOnly Property SMPCores() As Int16
        Get
            Return _SmpCores
        End Get
    End Property
    Public ReadOnly Property HasAffintyChanger() As Boolean
        Get
            Return _HasAffintyChanger
        End Get
    End Property
    Public ReadOnly Property CurrentUser() As String
        Get
            Return _strUserName
        End Get
    End Property
    Public ReadOnly Property IsAdmin() As Boolean
        Get
            Return _IsAdmin
        End Get
    End Property
    Public ReadOnly Property IsX64() As Boolean
        Get
            Return _X64
        End Get
    End Property
    Public ReadOnly Property OsName() As String
        Get
            Return _strOSName
        End Get
    End Property
    Public ReadOnly Property OSSupported() As Boolean
        Get
            Return _OsSupported
        End Get
    End Property
    Public ReadOnly Property TotalCores() As String
        Get
            Return _intCpuCoresTotal.ToString
        End Get
    End Property
    <Serializable()> _
    Public Structure InstalledGPU
        Dim DeviceID As String
        Dim DeviceName As String
        Dim AdapterRam As String
        Dim DeviceDescription As String
        Dim DriverVersion As String
        Dim InfSection As String
        Dim DriverDate As String
        Dim ResolvedBy As String
        Dim ClockSpeed As String
        Dim CanFold As Boolean
    End Structure
    <Serializable()> _
    Public Structure InstalledCPU
        Dim Name As String
        Dim Manufacturer As String
        Dim ClockSpeed As String
        Dim NumberOfCores As Int16
        Dim NumberOfLogicalCpus As Int16
        Public ReadOnly Property HasHT() As Boolean
            Get
                If NumberOfLogicalCpus <> NumberOfCores Then
                    Return True
                Else
                    Return False
                End If
            End Get
        End Property
    End Structure
    Private _colCpus As New Collection
    Private _colGpus As New Collection
    Public Sub AlwaysExtended()
        _DoExtended = True
    End Sub
    Public Sub RemoveExtended()
        _DoExtended = False
    End Sub
    Public ReadOnly Property GetCpu(ByVal Index As Int16) As InstalledCPU
        Get
            Return _colCpus(Index)
        End Get
    End Property
    Public ReadOnly Property GetGpu(ByVal Index As Int16) As InstalledGPU
        Get
            Return _colGpus(Index)
        End Get
    End Property
    Public Sub FillGpuCMB(ByVal cmbGpu As ComboBox)
        Try
            cmbGpu.Items.Clear()
            Dim ngpu As InstalledGPU
            For Each ngpu In _colGpus
                cmbGpu.Items.Add(ngpu.DeviceName)
            Next
            cmbGpu.Text = cmbGpu.Items(0).ToString
        Catch ex As Exception
            MsgBox("Error filling gpu combobox" & vbNewLine & ex.Message & vbNewLine & ex.InnerException.ToString)
        End Try
    End Sub
    Public Sub FillCpuCMB(ByVal cmbCpu As ComboBox)
        Try
            cmbCpu.Items.Clear()
            Dim nCpu As InstalledCPU
            For Each nCpu In _colCpus
                cmbCpu.Items.Add(nCpu.Name)
            Next
            cmbCpu.Text = cmbCpu.Items(0).ToString
        Catch ex As Exception
            MsgBox("Error filling cpu combobox" & vbNewLine & ex.Message & vbNewLine & ex.InnerException.ToString)
        End Try
    End Sub
    Public Enum eSMPtype
        None = 0
        Deino = 1
        Mpich = 2
    End Enum
    Public Sub FillTV(ByVal TVclients As TreeView, Optional ByVal Stype As eSMPtype = eSMPtype.None)
        Try
            TVclients.Nodes.Clear()
            TVclients.CheckBoxes = True
            Dim nGpu As InstalledGPU
            Dim nCpu As InstalledCPU

            If (hwInfo.TotalCores >= 2 And hwInfo.HasHT = False) Or hwInfo.TotalCores >= 4 Then
                For Each nCpu In _colCpus
                    For intX As Int16 = 1 To nCpu.NumberOfCores Step _SmpCores
                        Dim tCpu As New clsClientConfiguration.clsClientConfigs.sSetupManager.InstalledCPU
                        With tCpu
                            .ClockSpeed = nCpu.ClockSpeed
                            .NumberOfCores = nCpu.NumberOfCores
                            .NumberOfLogicalCpus = nCpu.NumberOfLogicalCpus
                            .Name = nCpu.Name
                            .Manufacturer = nCpu.Manufacturer
                        End With
                        If Stype = eSMPtype.Deino Then
                            Dim nNode As New TreeNode
                            With nNode
                                .Name = nCpu.Name
                                .Text = "SMP Deino on " & nCpu.Name
                                If WindowsPlatform = eWindowsPlatform.WindowsVista2008 Then
                                    .Tag = clsClientConfiguration.clsClientConfigs.eClient.SVD
                                Else
                                    .Tag = clsClientConfiguration.clsClientConfigs.eClient.SXD
                                End If
                                .Checked = True
                                TVclients.Nodes.Add(nNode)
                            End With
                        ElseIf Stype = eSMPtype.Mpich Then
                            Dim nNode As New TreeNode
                            With nNode
                                .Text = "SMP Mpich on " & nCpu.Name
                                If WindowsPlatform = eWindowsPlatform.WindowsVista2008 Then
                                    .Tag = clsClientConfiguration.clsClientConfigs.eClient.SVM
                                Else
                                    .Tag = clsClientConfiguration.clsClientConfigs.eClient.SXM
                                End If
                                .Checked = True
                                TVclients.Nodes.Add(nNode)
                            End With
                        Else
                            For xInt As Int16 = 1 To tCpu.NumberOfCores
                                Dim nNode As New TreeNode
                                With nNode
                                    .Text = "Uniprocessor client on " & nCpu.Name & " core " & xInt.ToString
                                    .Checked = True
                                    .Tag = clsClientConfiguration.clsClientConfigs.eClient.CPU
                                End With
                                TVclients.Nodes.Add(nNode)
                            Next
                        End If
                    Next
                Next
            End If
            For Each nGpu In _colGpus
                If nGpu.CanFold Then
                    Dim tGpu As New clsClientConfiguration.clsClientConfigs.sSetupManager.InstalledGPU
                    With tGpu
                        .AdapterRam = nGpu.AdapterRam
                        .CanFold = nGpu.CanFold
                        .DeviceDescription = nGpu.DeviceDescription
                        .DeviceID = nGpu.DeviceID
                        .DeviceName = nGpu.DeviceName
                        .DriverDate = nGpu.DriverDate
                        .DriverVersion = nGpu.DriverVersion
                        .InfSection = nGpu.InfSection
                        .ResolvedBy = nGpu.ResolvedBy
                    End With
                    Dim nNode As New TreeNode
                    With nNode
                        .Name = nGpu.DeviceName
                        If nGpu.DeviceID.Contains("VEN_" & pciNvidia) Then
                            If WindowsPlatform = eWindowsPlatform.WindowsVista2008 Then
                                .Tag = clsClientConfiguration.clsClientConfigs.sSetupManager.eClient.GVN
                            Else
                                .Tag = clsClientConfiguration.clsClientConfigs.sSetupManager.eClient.GXN
                            End If
                            .Text = "Gpu2 Nvidia client on " & nGpu.DeviceName
                        Else
                            If WindowsPlatform = eWindowsPlatform.WindowsVista2008 Then
                                .Tag = clsClientConfiguration.clsClientConfigs.sSetupManager.eClient.GVA
                            Else
                                .Tag = clsClientConfiguration.clsClientConfigs.sSetupManager.eClient.GXA
                            End If
                            .Text = "Gpu2 Ati client on " & nGpu.DeviceName
                        End If
                        .Checked = True
                    End With
                    TVclients.Nodes.Add(nNode)
                End If
            Next
            TVclients.Nodes(0).ExpandAll()
        Catch ex As Exception
            MsgBox("Error in filling the hw list" & vbNewLine & ex.Message & vbNewLine & ex.InnerException.ToString)
        End Try
    End Sub
    Public Sub AddToCfg()
        Try
            Dim nGpu As InstalledGPU
            Dim nCpu As InstalledCPU

            For Each nCpu In _colCpus
                For intX As Int16 = 1 To nCpu.NumberOfCores Step _SmpCores
                    Dim nNode As New TreeNode
                    With nNode
                        .Name = nCpu.Name
                        If _X64 Then
                            If WindowsPlatform = eWindowsPlatform.WindowsVista2008 Then
                                'Cfg.CfgManager.SetupManager.
                            End If
                        Else
                            .Text = "SMP DEINO on " & nCpu.Name
                        End If
                    End With

                Next
            Next

            For Each nGpu In _colGpus
                If nGpu.CanFold Then
                    Dim nNode As New TreeNode
                    With nNode
                        .Name = nGpu.DeviceName
                        If nGpu.DeviceID.Contains("VEN_" & pciNvidia) Then
                            .Text = "Gpu2 Nvidia client on " & nGpu.DeviceName
                        Else
                            .Text = "Gpu2 Ati client on " & nGpu.DeviceName
                        End If
                        .Checked = True
                    End With
                    'TVclients.Nodes.Add(nNode)
                End If
            Next
        Catch ex As Exception
            MsgBox("Error with adding client to configuration" & vbNewLine & ex.Message & vbNewLine & ex.InnerException.ToString)
        End Try
    End Sub
    Public Function HasRemovable() As Boolean
        Try
            For Each sD As DriveInfo In My.Computer.FileSystem.Drives
                If sD.DriveType = DriveType.Removable Then Return True
            Next
            Return False
        Catch ex As Exception
            MsgBox("Can not determine removable drive existence")
            Return False
        End Try
    End Function
    Public Sub doWMI(Optional ByVal Silent As Boolean = False)
        Try
            _SmpCores = 4 'Cam be edited for dual smp on quads
            If Not Silent Then
                Message = New frmMessage
                'clspcidatabase
                With Message
                    .ControlBox = False
                    .Text = "Collecting platform information"
                    .lblMessage.Text = "Getting platform type x86/x64"
                    .cmdCancel.Visible = False
                    .cmdOK.Text = "&Done"
                    .cmdOK.Enabled = False
                    .pbar.Width = 432
                    .Show()
                    Application.DoEvents()
                End With
            End If

            If IntPtr.Size = 8 Then
                'win64
                _X64 = True
            ElseIf IntPtr.Size = 4 Then
                'win32
                _X64 = False
            End If

            If Not Silent Then
                With Message
                    .lblMessage.Text = "Using WMI for Gpu identification"
                    Application.DoEvents()
                End With
            End If
            Dim bHasNvidia As Boolean = False

            Dim query As ObjectQuery
            query = New ObjectQuery("SELECT * FROM Win32_VideoController")
            Dim searcher As ManagementObjectSearcher
            searcher = New ManagementObjectSearcher(query)
            Dim queryCollection As ManagementObjectCollection
            queryCollection = searcher.Get()
            For Each m As ManagementObject In queryCollection
                Dim nGpu As New InstalledGPU
                nGpu.DeviceID = m.GetPropertyValue("PNPDeviceID")
                If Mid(m.GetPropertyValue("PNPDeviceID"), 9, 4) = pciNvidia Then
                    With nGpu
                        .DeviceName = m.GetPropertyValue("Caption")
                        .DeviceDescription = m.GetPropertyValue("Description")
                        .DriverVersion = m.GetPropertyValue("DriverVersion")
                        .DriverDate = m.GetPropertyValue("Driverdate")
                        .AdapterRam = (m.GetPropertyValue("AdapterRAM") / 1024 / 1024).ToString & "MB"
                        .InfSection = m.GetPropertyValue("InfSection")  '"nv_G9x_HD"
                        'Resolve canfold 

                        If Not Silent Then
                            With Message
                                .lblMessage.Text = "Using CUDA for NVIDIA gpu folding capabilities."
                                Application.DoEvents()
                            End With
                        End If

                        Dim bHasResetCuda As Boolean = False
ResetCuda:
                        Dim nCuda As New GASS.CUDA.CUDA
                        Try
                            nCuda.Init()
                            If nCuda.LastError <> CUResult.Success Then
                                If bHasResetCuda Then
                                    MsgBox("Setup could not initialise cuda.net" & vbNewLine & vbNewLine & "Application can not continue")
                                    Application.Exit()
                                End If
                                If DownloadCUDA() Then
                                    bHasResetCuda = True
                                    GoTo ResetCuda
                                End If
                            End If
                        Catch ex As Exception
                            If bHasResetCuda Then
                                MsgBox("Setup could not initialise cuda.net" & vbNewLine & vbNewLine & "Application can not continue")
                                Application.Exit()
                            End If
                            bHasResetCuda = True
                            GoTo ResetCuda
                        End Try

                        Try
                            nGpu.CanFold = False
                            For Each cDevice As Device In nCuda.Devices
                                Dim strA As String = nGpu.DeviceName.ToUpper.Replace("NVIDIA", "").Trim
                                Dim strB As String = cDevice.Name.ToUpper.Trim
                                If strA.Equals(strB) Or strA.Contains(strB) Or strB.Contains(strA) Then
                                    nGpu.CanFold = True
                                    nGpu.ClockSpeed = cDevice.Properties.ClockRate.ToString
                                End If
                            Next
                        Catch ex As Exception

                        End Try
                    End With
                    _colGpus.Add(nGpu, nGpu.DeviceID)
                ElseIf Mid(m.GetPropertyValue("PNPDeviceID"), 9, 4) = pciAti Then
                    '"PCI\VEN_10DE&DEV_0622&SUBSYS_23651682&REV_A1\4&F3A193A&0&0008" 0622 = 9600gt
                    With nGpu
                        .DeviceName = m.GetPropertyValue("Caption")
                        .DeviceDescription = m.GetPropertyValue("Description")
                        .DriverVersion = m.GetPropertyValue("DriverVersion")
                        .DriverDate = m.GetPropertyValue("Driverdate")
                        .AdapterRam = (m.GetPropertyValue("AdapterRAM") / 1024 / 1024).ToString & "MB"
                        .InfSection = m.GetPropertyValue("InfSection")  '"nv_G9x_HD"
                        'Resolve canfold 
                        If Not Silent Then
                            With Message
                                .lblMessage.Text = "Using name resolve for Ati folding capabilities."
                                Application.DoEvents()
                            End With
                        End If
                        .CanFold = CanFold(nGpu)
                    End With
                    _colGpus.Add(nGpu, nGpu.DeviceID)
                End If
            Next

            If Not Silent Then
                With Message
                    .lblMessage.Text = "Getting windows version"
                    Application.DoEvents()
                End With
            End If
            
            _strOSName = GetOSVersion()
            If Environment.OSVersion.Version.Major < 5 Or (Environment.OSVersion.Version.Major = 5 And Environment.OSVersion.Version.Minor = 0) Then
                _OsSupported = False
            Else
                If Environment.OSVersion.Version.Major = 6 Then
                    _WinPlatform = eWindowsPlatform.WindowsVista2008
                ElseIf Environment.OSVersion.Version.Major = 5 And Environment.OSVersion.Version.Minor = 1 Then
                    _WinPlatform = eWindowsPlatform.WindowsXP
                ElseIf Environment.OSVersion.Version.Major = 5 And Environment.OSVersion.Version.Minor = 2 Then
                    _WinPlatform = eWindowsPlatform.Windows2003
                End If
                _OsSupported = True
            End If

            If Not Silent Then
                With Message
                    .lblMessage.Text = "Getting current user information"
                    Application.DoEvents()
                End With
            End If
            
            Dim mIdentity As System.Security.Principal.WindowsIdentity = WindowsIdentity.GetCurrent()
            _strUserName = mIdentity.Name
            Dim mPrincipal = New WindowsPrincipal(mIdentity)

            Debug.Print(mPrincipal.IsInRole(WindowsBuiltInRole.User))
            Debug.Print(mPrincipal.IsInRole(WindowsBuiltInRole.SystemOperator))
            Debug.Print(mPrincipal.IsInRole(WindowsBuiltInRole.Replicator))
            Debug.Print(mPrincipal.IsInRole(WindowsBuiltInRole.PrintOperator))
            Debug.Print(mPrincipal.IsInRole(WindowsBuiltInRole.PowerUser))
            Debug.Print(mPrincipal.IsInRole(WindowsBuiltInRole.Guest))
            Debug.Print(mPrincipal.IsInRole(WindowsBuiltInRole.BackupOperator))
            Debug.Print(mPrincipal.IsInRole(WindowsBuiltInRole.Administrator))
            Debug.Print(mPrincipal.IsInRole(WindowsBuiltInRole.AccountOperator))

            If mPrincipal.IsInRole(WindowsBuiltInRole.Administrator) Then
                _IsAdmin = True
            Else
                _IsAdmin = False
            End If


            If InstalledDOTNETVersion < eDotNetVersion.ThreePointFive Then
                If Not Silent Then
                    With Message
                        .lblMessage.Text = "Using WMI for Cpu identification"
                        Application.DoEvents()
                    End With
                End If
                Try
                    query = New ObjectQuery("SELECT * FROM Win32_Processor")
                    searcher = New ManagementObjectSearcher(query)
                    queryCollection = searcher.Get()
                    For Each m As ManagementObject In queryCollection
                        Dim nCpu As New InstalledCPU
                        With nCpu
                            .NumberOfCores = m.GetPropertyValue("NumberOfCores")
                            _intCpuCoresTotal += CInt(.NumberOfCores)
                            _intCpuCount += 1
                            .NumberOfLogicalCpus = m.GetPropertyValue("NumberOfLogicalProcessors")
                            .Name = m.GetPropertyValue("Name")
                            .Manufacturer = m.GetPropertyValue("Manufacturer")
                            .ClockSpeed = m.GetPropertyValue("CurrentClockSpeed")
                            If .NumberOfLogicalCpus <> .NumberOfCores Then hwInfo.HasHT = True
                        End With
                        _colCpus.Add(nCpu)
                    Next
                Catch ex As Exception
                    GoTo UseRegistry
                End Try
            Else
UseRegistry:
                If Not Silent Then
                    With Message
                        .lblMessage.Text = "Using registry for cpu information"
                        Application.DoEvents()
                    End With
                End If
                Dim cpuReg As New clsCpuReg
                If cpuReg.HasError Then
                    MsgBox("Could not use alternate method of cpu identification." & vbNewLine & cpuReg.LastError.Description & vbNewLine & vbNewLine & _
                           "Both WMI and registry fails to identify the number of cores, installer can not continue", MsgBoxStyle.OkOnly + MsgBoxStyle.Critical)
                    End
                End If
                Dim nCpu As New InstalledCPU
                With nCpu
                    .NumberOfCores = cpuReg.NumberOfEntries
                    _intCpuCoresTotal = cpuReg.NumberOfEntries
                    _intCpuCount = cpuReg.NumberOfEntries
                    .NumberOfLogicalCpus = cpuReg.NumberOfEntries
                    .Name = cpuReg.Core(1)
                End With
                _colCpus.Add(nCpu)
            End If

            _DestFolder = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) & "\" & Application.CompanyName
            If Not Silent Then
                With Message
                    .lblMessage.Text = "Done"
                    Application.DoEvents()
                    .Close()
                End With
            End If
        Catch ex As Exception
            MsgBox("Error while executing wmi queries" & vbNewLine & ex.Message & vbNewLine & ex.InnerException.ToString & vbNewLine & vbNewLine & "Installer can not continue.", MsgBoxStyle.OkOnly + MsgBoxStyle.Critical)
            End
        End Try
    End Sub
    Private ReadOnly Property CanFold(ByVal Gpu As InstalledGPU) As Boolean
        Get
            Try
                Dim vendID As String
                Dim devID As String
                '"PCI\VEN_10DE&DEV_0622&SUBSYS_23651682&REV_A1\4&F3A193A&0&0008" 0622 = 9600gt
                vendID = Mid(Gpu.DeviceID, InStr(Gpu.DeviceID, "VEN_") + 4, 4)
                devID = Mid(Gpu.DeviceID, InStr(Gpu.DeviceID, "DEV_") + 4, 4)
                If vendID = pciAti Then
                    If Gpu.DeviceName.ToUpper.Contains("HD 2") Or Gpu.DeviceName.ToUpper.Contains("HD 3") Or Gpu.DeviceName.ToUpper.Contains("HD 4") Or Gpu.DeviceName.ToUpper.Contains("HD 5") Or Gpu.DeviceName.ToUpper.Contains("HD2") Or Gpu.DeviceName.ToUpper.Contains("HD3") Or Gpu.DeviceName.ToUpper.Contains("HD4") Or Gpu.DeviceName.ToUpper.Contains("HD5") Then Return True
                    If Gpu.DeviceName.ToUpper.Contains("R6") Or Gpu.DeviceName.ToUpper.Contains("R 6") Or Gpu.DeviceName.ToUpper.Contains("RV6") Or Gpu.DeviceName.ToUpper.Contains("RV 6") Or Gpu.DeviceName.ToUpper.Contains("RV7") Or Gpu.DeviceName.ToUpper.Contains("RV 7") Then Return True
                    Return False
                End If
                Return False
            Catch ex As Exception
                Return False
            End Try
        End Get
    End Property
    Public Function GetOSVersion() As String
        Try
            Select Case Environment.OSVersion.Platform
                Case PlatformID.Win32S
                    Return "Win 3.1"
                Case PlatformID.Win32Windows
                    Select Case Environment.OSVersion.Version.Minor
                        Case 0
                            Return "Win95"
                        Case 10
                            Return "Win98"
                        Case 90
                            Return "WinME"
                        Case Else
                            Return "Unknown"
                    End Select
                Case PlatformID.Win32NT
                    Select Case Environment.OSVersion.Version.Major
                        Case 3
                            Return "NT 3.51"
                        Case 4
                            Return "NT 4.0"
                        Case 5
                            Select Case Environment.OSVersion.Version.Minor
                                Case 0
                                    Return "Win2000"
                                Case 1
                                    Return "WinXP"
                                Case 2
                                    Return "Win2003"
                            End Select
                        Case 6
                            Return "Vista/Win2008Server"
                        Case Else
                            Return "Unknown"
                    End Select
                Case PlatformID.WinCE
                    Return "Win CE"
                Case Else
                    Return "Unkown"
            End Select
            Return "Unknown"
        Catch ex As Exception
            Return "Error"
        End Try
    End Function
End Class
